为自定义项目实现同步器逻辑

您所在的位置:网站首页 blender smooth笔刷在哪 为自定义项目实现同步器逻辑

为自定义项目实现同步器逻辑

2023-03-30 12:59| 来源: 网络整理| 查看: 265

编程PluginsSyncker PluginImplementing Syncker Logic for a Custom Project 为自定义项目实现同步器逻辑 警告 本文介绍的功能在 Community SDK 版本中不可用。 您应该升级到 Sim SDK版本才能使用它。 章节: 初始化同步器同步节点/材料在运行时创建/删除节点在运行时加载节点通过用户消息自定义同步同步地形修改更改视图和相机 Initializing Syncker初始化同步器#

First of all, you should initialize Syncker. To do so you can simply add the following code to the AppSystemLogic class for both Master and Slave applications.首先,您应该初始化 Syncker。为此,您可以简单地将以下代码添加到 Master 和 Slave 应用程序的 AppSystemLogic 类中。

Insert the following Syncker initialization code to the AppSystemLogic::init() method:将以下 Syncker 初始化代码插入到 AppSystemLogic::init() 方法中:

源代码 (C++)// AppSystemLogic.cpp #include "AppSystemLogic.h" #include /* .. */ using namespace Unigine; using namespace Plugins; /* .. */ int AppSystemLogic::init() { // update application even if focus was lost Engine::get()->setBackgroundUpdate(true); // get the Syncker manager interface Syncker::Manager *syncker_manager = Syncker::Manager::get(); // initialize the Syncker using command line arguments // or you can initialize Syncker as Master or Slave directly // via initMaster() or initSlave() methods without using command-line arguments syncker_manager->initSyncker(); // enable debug information in right bottom corner syncker_manager->getSyncker()->setDebug(true); return 1; }

In the AppWorldLogic.cpp file add the code to get the pointer to the manager and Master interface for further use in the AppWorldLogic::init() method:在 AppWorldLogic.cpp 文件中添加代码以获取指向 manager 和 Master 接口的指针,以便在 AppWorldLogic::init() 方法中进一步使用:

源代码 (C++)// AppWorldLogic.cpp #include #include /* .. */ using namespace Unigine; using namespace Syncker; using namespace Math; int AppWorldLogic::init() { Syncker::Manager *syncker_manager = Syncker::Manager::get(); if (syncker_manager && syncker_manager->isMasterInitialized()) syncker_master = syncker_manager->getMaster(); return 1; } Synchronizing Nodes/Materials同步节点/材料#

Objects of the following types are synchronized automatically: ObjectWaterGlobal, ObjectCloudLayer, ObjectParticles, WorldLight if they present in the *.world file on all computers.以下类型的对象会自动同步: ObjectWaterGlobal, ObjectCloudLayer, ObjectParticles, WorldLight 如果它们出现在所有计算机上的 *.world 文件中。

Synchronization of transformations is supported for all types of nodes. As for other type-specific parameters synchronization is available only for the following ones:所有类型的节点都支持转换同步。至于其他类型特定的参数同步仅适用于以下参数:

NodeDummy NodeReference FieldAnimation FieldHeight FieldWeather LightEnvironmentProbe LightOmni LightProj LightWorld ObjectMeshStatic ObjectMeshSkinned ObjectParticles ObjectVolumeSphere ObjectVolumeBox ObjectVolumeOmni ObjectVolumeProj ObjectWaterGlobal ObjectWaterMesh ObjectSky ObjectCloudLayer NodeExtern ObjectExtern WorldExtern WorldTransformBone PlayerDummy PlayerSpectator PlayerActor 注意Automatic synchronization of run-time changes of the Global Terrain object is not supported, but it can be implemented manually using custom messages.不支持自动同步 Global Terrain 对象的运行时更改,但可以手动实现使用自定义消息.

To start synchronizing other nodes or materials (the logic is the same for both), that exist in the world, you just need to tell Syncker which of them you want. To do so you can add the following code to the AppWorldLogic::init() method of your master application:要开始同步世界上存在的其他节点或材料(两者的逻辑相同),您只需要告诉 Syncker 您想要其中的哪一个。为此,您可以将以下代码添加到主应用程序的 AppWorldLogic::init() 方法中:

源代码 (C++)int AppWorldLogic::init() { /* ... */ // checking if we have a Master interface if (syncker_master) { // getting a pointer for the node named "material_ball" NodePtr my_node = World::getNodeByName("material_ball"); // add the existing node to synchronization syncker_master->addSyncNode(my_node, Master::SYNC_MASK::TRANSFORM); } return 1; }

Now, you can implement your logic for synchronized nodes in the AppWorldLogic::update() method for Master:现在,您可以在 Master 的 AppWorldLogic::update() 方法中实现同步节点的逻辑:

源代码 (C++)int AppWorldLogic::update() { /* ... */ // checking if we have a Master interface if (syncker_master) { // getting a pointer for the node named "material_ball" NodePtr my_node = World::getNodeByName("material_ball"); // changing node's rotation my_node->setRotation(my_node->getRotation() * Math::quat(0, 0, Game::getIFps())); } return 1; } Creating/Deleting Nodes at Runtime在运行时创建/删除节点#

You can create and delete nodes at run time. To synchronize creation of a node on all connected Slave PCs, use the createNode() function.您可以在运行时创建和删除节点。要在所有连接的 Slave PC 上同步节点的创建,请使用 createNode() 函数。

注意Please note, that the createNode() method support only a limited number of node types, so it is recomended to load nodes from *.node files instead.请注意,createNode() 方法仅支持有限数量的节点类型,因此建议使用负载节点来自 *.node 文件。 源代码 (C++)/* ... */ int cube_created = 0; int AppWorldLogic::update() { /* ... */ // checking if we have a Master interface and cube is not yet created if (syncker_master && !cube_created) { // creating a dynamic cube and set up its material and transformation ObjectMeshStaticPtr dynamic_cube = ObjectMeshStatic::create("box.mesh"); dynamic_cube->setMaterial("mesh_base", 0); dynamic_cube->setPosition(Math::Vec3(game->getRandomFloat(-50, 50), game->getRandomFloat(-50, 50), game->getRandomFloat(0, 50))); dynamic_cube->setRotation(Math::quat(game->getRandomFloat(0, 360), game->getRandomFloat(0, 360), game->getRandomFloat(0, 360))); // commanding Slaves to create a dynamic node and adding it to synchronization syncker_master->createNode(dynamic_cube); cube_created = 1; } return 1; } 注意For this code to be compiled, copy the box.mesh file from the /data/samples/common/meshes folder to the /data//meshes folder.要编译此代码,请将 box.mesh 文件从 /data/samples/common/meshes 文件夹复制到 /data//meshes 文件夹。 Loading Nodes at Runtime在运行时加载节点#

To synchronize node loading from a *.node file on all connected Slave PCs, use the loadNode() or loadNodereference() methods. This approach is recommended as it allows adding nodes of all types, unlike the createNode() method that supports only a limited number of them.要从所有连接的 Slave PC 上的 *.node 文件同步节点加载,请使用 loadNode() 或 loadNodereference() 方法。推荐使用这种方法,因为它允许添加所有类型的节点,这与仅支持有限数量的 createNode() 方法不同。

源代码 (C++)/* ... */ int node_loaded = 0; int AppWorldLogic::update() { /* ... */ // checking if we have a Master interface and our node is not yet loaded if (syncker_master && !node_loaded) { // commanding Slaves to load a node and adding it to synchronization syncker_master->loadNode("my_node.node", Master::SYNC_MASK::NODE_FLAGS | Master::SYNC_MASK::TRANSFORM); node_loaded = 1; } return 1; } Customizing Synchronization via User Messages通过用户消息自定义同步#

Let us consider the following simple example: we can set transformation for a node, by simply sending rotation and position via a user message.让我们考虑下面这个简单的例子:我们可以为一个节点设置变换,只需通过一个用户留言.

First step is to create an object on Master and on all Slave PCs as a static one (without adding it to synchronization).第一步是在 Master 和所有 Slave PC 上创建一个对象作为静态对象(不将其添加到同步中)。

Next, we implement a callback function:接下来,我们实现一个回调函数:

on_message_received — to be called on receiving a user message. Here we extract the parameters from the received message and use them (in this case to change node's transformation).on_message_received — 在接收用户消息时调用。在这里,我们从接收到的消息中提取参数并使用它们(在本例中用于更改节点的转换)。

And the last step is to set this callback using the setMessageReceivedCallback() method in AppWorldLogic::init()最后一步是使用 AppWorldLogic::init() 中的 setMessageReceivedCallback() 方法设置此回调

源代码 (C++)// declaring and initializing pointers for the Master, Slave, and Syncker instances Unigine::Plugins::Syncker::Master *master = nullptr; Unigine::Plugins::Syncker::Slave *slave = nullptr; Unigine::Plugins::Syncker::Syncker *syncker = nullptr; // declaring a node, that we are going to transform via user messages NodePtr node; // declaring a blob to store our messages Unigine::BlobPtr blob = Unigine::Blob::create(); // declaring message types to be used enum MESSAGE_TYPE { REPORT, TRANSFORM, }; /* ... */ /// callback function to be fired on receiving a user message void AppWorldLogic::on_message_received(const Unigine::BlobPtr &message) { // reading an unsigned char from the blob defining message type (REPORT or TRANSFORM) unsigned char type = message->readUChar(); switch (type) { case REPORT: { // printing to the console that we have received a message Log::message("REPORT Message received!") } break; case TRANSFORM: { // reading position and rotation from the message and using them to update node's transformation Vec3 pos = Vec3(message->readDVec3()); quat rot = message->readQuat(); node->setTransform(translate(pos) * Mat4(rotate(rot))); } break; } } int AppWorldLogic::init() { /* ... */ // trying to get a Manager interface auto manager = Syncker::Manager::get(); if (manager) { // checking if we have a Master interface if (manager->isMasterInitialized()) master = manager->getMaster(); else if (manager->isSlaveInitialized()) slave = manager->getSlave(); // getting a pointer to Master/Slave base class syncker = manager->getSyncker(); } // subscribing to network messages if (syncker) syncker->setMessageReceivedCallback("net", MakeCallback(this, &AppWorldLogic::on_message_received)); /* ... */ // somwhere in code... sending a REPORT message blob->clear(); blob->writeUChar(REPORT); syncker->sendMessage("net", blob); return 1; } int AppWorldLogic::update() { /* ... */ // sending a message with object's transform to all peers if (master) { Vec3 pos = node->getPosition(); quat rot = node->getRotation(); blob->clear(); blob->writeUChar(TRANSFORM); blob->writeDVec3(dvec3(pos)); blob->writeQuat(rot); syncker->sendMessage("net", blob); } /* ... */ return 1; } Synchronizing Terrain Modifications同步地形修改#

Run-time changes of the Global Terrain object are not synchronized automatically, but you can do it manually using custom messages:Global Terrain 对象的运行时更改不会自动同步,但您可以使用自定义消息手动进行:

源代码 (C++)ObjectTerrainGlobalPtr terrain; Plugins::Syncker::Manager syncker_manager; int AppWorldLogic::init() { // getting the terrain object (this operation is performed once, so it should be in the init() method) terrain = checked_ptr_cast(World::getNodeByType(Node::OBJECT_TERRAIN_GLOBAL)); // for Slave syncker_manager = Plugins::Syncker::Manager::get(); if (syncker_manager) { auto slave = syncker_manager->getSlave(); if (slave) { // set the on_terrain_update() method to be called on receiving the "terrain_update" message by a Slave. slave->setMessageReceivedCallback("terrain_update", MakeCallback(this, &AppWorldLogic::on_terrain_update)); } } return 1; } /// Method updating the Terrain void AppWorldLogic::update_terrain(int detail, float threshold, float width, float contrast) { // apply parameters to terrain terrain->getDetail(detail)->setMaskThreshold(threshold); terrain->getDetail(detail)->setMaskWidth(width); terrain->getDetail(detail)->setMaskContrast(contrast); if (syncker_manager) { auto master = syncker_manager->getMaster(); if (master) { // send the "terrain_update" message with parameters BlobPtr blob = Blob::create(); blob->writeInt(detail); blob->writeFloat(threshold); blob->writeFloat(width); blob->writeFloat(contrast); master->sendMessage("terrain_update", blob); } } } void AppWorldLogic::on_terrain_update(const Unigine::BlobPtr &message) { // read parameters from the message in the same order int detail = message->readInt(); float threshold = message->readFloat(); float width = message->readFloat(); float contrast = message->readFloat(); // invoke update_terrain to apply parameters update_terrain(detail, threshold, width, contrast); } int AppWorldLogic::update() { // for the Master if (Input::isKeyPressed(Input::KEY_T)) { update_terrain(1, 2.0, 3.0f, 4.0f); } return 1; } Changing Views and Cameras更改视图和相机#

You can change the viewport on the Master or Slave side. For this purpose you can use the following code (example):您可以更改 Master 或 Slave 侧的视口。为此,您可以使用以下代码(示例):

源代码 (C++)Unigine::Plugins::Syncker::Manager* syncker_manager; /* ... perform checks if the Syncker plugin is loaded and get the Syncker manager interface (Manager) ... */ // if syncker is initialized, assigning the config mesh surface named "surface_0" to the 2nd monitor if (syncker_manager->isSynckerIntialized()) syncker_manager->getSyncker()->setView(1, "surface_0"); /* ... */

You can also tell Slave to use another camera. To do so, you can use the following code (example):您还可以告诉 Slave 使用另一台相机。为此,您可以使用以下代码(示例):

源代码 (C++)/* ... */ PlayerSpectatorPtr aux_player = nullptr; /* ... */ int AppWorldLogic::update() { /* ... */ // checking if we have a Master interface if (syncker_master && !aux_player) { // creating a new auxiliary player (on Master and Slaves) aux_player = PlayerSpectator::create(); aux_player->setPosition(Vec3(0.0f, -40.0f, 200.0f)); aux_player->setDirection(vec3(0.0f, 1.0f, 0.0f), vec3_up); aux_player->setMinVelocity(10); aux_player->setMaxVelocity(aux_player->getMinVelocity() * 2); // commanding Slaves to create a new player and adding it to synchronization syncker_master->createNode(aux_player, ~0); // setting a new created player for Slave(s) having sync_view = "view_1" syncker_master->setSlavePlayer("view_1", aux_player); } /* ... */ } 最新更新: 2022-12-14


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3